package eu.robico.simulator.simulatorinterface.actionpanel.objects;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;

import eu.robico.simulator.simulatorinterface.MainController;
import eu.robico.simulator.simulatorinterface.actionpanel.Position;
import eu.robico.simulator.simulatorinterface.communication.Protocol.Trigger;
import eu.robico.simulator.simulatorinterface.utils.Boundary;
import eu.robico.simulator.simulatorinterface.utils.Toolkit;

class DistanceSensor implements RobotComponent 
{
	private class DistanceSensorObject
	{
		public void paint(Graphics2D graphics) 
		{
			Color sensorColor = (seesObstacle) ? Color.green : Color.magenta;
			graphics.setColor(sensorColor);
			graphics.fillRect((int) x - (LENGTH / 2), (int) y - (WIDTH / 2), LENGTH, WIDTH);
			
			Composite originalComposite = graphics.getComposite();
			graphics.setComposite(makeComposite(0.5f));
			graphics.fillRect((int) x + (LENGTH / 2), (int) y - WIDTH, VISION, WIDTH * 2);
			graphics.setComposite(originalComposite);
		}
	}
	
	private static final int LENGTH = 16;
	private static final int WIDTH = 6;
	
	private static final int VISION = 35;
	
	private DistanceSensorObject distaceSensorObject;
	private Robot robot;
	private Position centerPosition;
	private double x, y, rotation, distanceToRobotCenter;
	private boolean seesObstacle = false;
	
	public DistanceSensor(Robot robot, Position location, double rotation)
	{
		this.robot = robot;
		this.x = location.x;
		this.y = location.y;
		this.rotation = rotation;
		
		distaceSensorObject = this.new DistanceSensorObject();
	}
	
	private boolean seesObstacle(ObstacleObject obstacle)
	{
		//Our vision consists of a rectangle width twice the width of the sensor that starts at the end of the sensor and reaches as far as the VISION variable
		double distanceToRobotCenter = Toolkit.getDistance(centerPosition, robot.getPosition());
		Position startPosition = new Position(
				robot.getPosition().getX() + distanceToRobotCenter + (LENGTH / 2) + (VISION / 2),
				robot.getPosition().getY()
		);
		//Create vision bounds
		Boundary visionBounds = Boundary.getRectangleBounds(startPosition, VISION, WIDTH * 2);
		//Rotate vision bounds
		visionBounds = visionBounds.rotateAroundPosition(robot.getPosition(), rotation);
		//Get obstacle bounds
		Boundary obstacleBounds = Boundary.getRectangleBounds(obstacle.getPosition(), obstacle.getWidth());
		//Check for collisions
		return visionBounds.colidesWith(obstacleBounds);
	}
	
	private AlphaComposite makeComposite(float alpha) 
	{
		  return(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
	}
	
	//RobotComponent implementation below
	
	@Override
	public void update()
	{
		
		for (ActionPanelObject object : robot.getActionPanel().getObjects())
			if (object instanceof ObstacleObject && seesObstacle((ObstacleObject) object))
			{
				if (!seesObstacle)
				{
					MainController.getInstance().sendTrigger(Trigger.PROXIMITYTOGGLE);
					seesObstacle = true;
				}
				return;
			}
		//No obstacles detected
		if (seesObstacle)
		{
			MainController.getInstance().sendTrigger(Trigger.PROXIMITYTOGGLE);
			seesObstacle = false;
		}
	}
	
	@Override
	public void paint(Graphics2D graphics) 
	{
		distaceSensorObject.paint(graphics);
	}

	@Override
	public double getRotation() 
	{
		return rotation;
	}

	@Override
	public void setRotation(double rotation) 
	{
		this.rotation = rotation;
	}

	@Override
	public void setTrueCenter(Position centerPoint) 
	{
		this.centerPosition = centerPoint;
	}

	@Override
	public Position getTrueCenter() 
	{
		return centerPosition;
	}

	@Override
	public double getX() 
	{
		return x;
	}

	@Override
	public double getY() 
	{
		return y;
	}

	@Override
	public void setX(double x) 
	{
		this.x = x;
	}

	@Override
	public void setY(double y) 
	{
		this.y = y;
	}

	@Override
	public RobotComponentType getType() 
	{
		return RobotComponentType.DistanceSensor;
	}
	
	@Override
	public Position getPosition() 
	{
		return new Position(x, y);
	}

	@Override
	public double getDistanceToRobotCenter() 
	{
		return distanceToRobotCenter;
	}

	@Override
	public void setDistanceToRobotCenter(double distanceToRobotCenter) 
	{
		this.distanceToRobotCenter = distanceToRobotCenter;
	}
}
